package com.fitso.model.dao;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;

import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.BeanUtils;

import com.fitso.model.bean.User;
import com.fitso.model.exception.DuplicateUserException;

/**
 * Abstract test that verifies behavior of any implementation of {@link UserDao}
 * 
 * @author timothystorm
 */
public abstract class UserDaoDB_IT extends DatabaseIntegrationTestUnit {
	protected UserDao dao;
	
	protected User user;

	public abstract UserDao newUserDao();

	@Before
	public void setUp() throws Exception {
		super.setUp();
		dao = newUserDao();

		user = new User();
		user.setEmail("UserDaoDB_IT@fitso.com");
		user.setPassword("super_secret");
		user.setFirstName("Eric");
		user.setLastName("Cartman");
	}

	@Test
	public void test_delete() {
		User user = dao.readById(3L);
		assertNotNull(user);

		dao.delete(user);

		User fetchedUser = dao.readById(3L);
		assertNull(fetchedUser);
	}

	@Test
	public void test_delete_non_persisted() {
		try {
			dao.delete(user);
		}
		catch (Exception e) {
			fail("deleting a non-persisted user shouldn't do anything");
		}
	}

	@Test
	public void test_round_tripping() {
		String newPass = "anotherSecret";

		// verify this user doesn't already exist
		User fetchedUser = dao.readByEmail(user.getEmail());
		assertNull(fetchedUser);

		// save a new user
		dao.createOrUpdate(user);

		// pull that user back out
		fetchedUser = dao.readByEmail(user.getEmail());
		assertNotNull(fetchedUser);
		assertEquals(user.getPassword(), fetchedUser.getPassword());

		// update the user
		fetchedUser.setPassword(newPass);
		dao.createOrUpdate(fetchedUser);

		// pull that user back out and verify the change
		fetchedUser = dao.readByEmail(user.getEmail());
		assertNotNull(fetchedUser);
		assertEquals(newPass, fetchedUser.getPassword());

		// delete the user
		dao.delete(fetchedUser);

		// try and pull the user back out
		fetchedUser = dao.readByEmail(user.getEmail());
		assertNull(fetchedUser);
	}

	@Test
	public void test_update() {
		User user = dao.readById(3L);
		assertNotNull(user);

		user.setFirstName("NewName");
		dao.createOrUpdate(user);

		User fetchedUser = dao.readById(3L);
		assertEquals(user, fetchedUser);
	}

	@Test(expected = DuplicateUserException.class)
	public void test_saveOrUpdate_duplicate() throws Exception {
		User userCopy = new User();
		BeanUtils.copyProperties(user, userCopy);

		dao.createOrUpdate(user);
		dao.createOrUpdate(userCopy);
	}
}
